<?php
require_once 'Zend/Validate/Abstract.php';

class HTech_Validate_Date extends Zend_Validate_Abstract
{
    const MSG_FORMAT = 'msgFormat';
    const MSG_DATE = 'msgDate';    
    const MSG_MINDATE = 'msgMinDate';
    const MSG_MAXDATE = 'msgMaxDate';    
    const MSG_MINDATE_STRICT = 'msgMinDateStrict';
    const MSG_MAXDATE_STRICT = 'msgMaxDateStrict';
    const MSG_WEEKEND = 'msgWeekend';
    const MSG_WEEKDAY = 'msgWeekday';
     
    protected $_minDate;
    protected $_maxDate;
    protected $_minInclusive = false;
    protected $_maxInclusive = false;
    protected $_weekend = false;
    protected $_weekday = false;
     
    protected $_messageVariables = array(
        'minDate' => '_minDate',
        'maxDate' => '_maxDate'
    );
     
    protected $_messageTemplates = array(
        self::MSG_FORMAT  => "Valid format: yyyy-mm-dd",
        self::MSG_DATE    => "Invalid date, valid format: yyyy-mm-dd",
        self::MSG_MINDATE => "Minimum date allowed: %minDate%",
        self::MSG_MAXDATE => "Maximum date allowed: %maxDate%",
        self::MSG_MINDATE_STRICT => "Minimum date should be after %minDate%",
        self::MSG_MAXDATE_STRICT => "Maximum date should be before %maxDate%",
        self::MSG_WEEKEND => "Date is not weekend",
        self::MSG_WEEKDAY => "Date is weekend");
    
    public function __construct($options = array()) 
    {
        $value = '';
        if(is_array($options)) {
            if (array_key_exists('minDate', $options)) {
                if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $options['minDate'])) {
                    list($year, $month, $day) = sscanf($value, '%d-%d-%d');
                    if (!checkdate($month, $day, $year)) {
                        $this->_minDate = $options['minDate'];
                    }
                }             
            }
            if (array_key_exists('maxDate', $options)) {
                if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $options['maxDate'])) {
                    list($year, $month, $day) = sscanf($value, '%d-%d-%d');
                    if (!checkdate($month, $day, $year)) {
                        $this->_maxDate = $options['maxDate'];
                    }
                }             
            }   
            if (array_key_exists('weekend', $options)&&is_bool($options['weekend'])) {
                $this->_weekend = $options['weekend'];
            }     
            if (array_key_exists('weekday', $options)&&is_bool($options['weekday'])) {
                $this->_weekday = $options['weekday'];
            }  
            if (array_key_exists('minInclusive', $options)&&is_bool($options['minInclusive'])) {
                $this->_minInclusive = $options['minInclusive'];
            } 
            if (array_key_exists('maxInclusive', $options)&&is_bool($options['maxInclusive'])) {
                $this->_maxInclusive = $options['maxInclusive'];
            }
        }
    }
     
    public function isValid($value)
    {
        $this->_setValue($value);
            
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
            $this->_error(self::MSG_FORMAT);
            return false;
        }

        list($year, $month, $day) = sscanf($value, '%d-%d-%d');
        if (!checkdate($month, $day, $year)) {
            $this->_error(self::MSG_DATE);
            return false;
        }
        
        if ($this->_minInclusive) {
            if (isset($this->_minDate)&&($value < $this->_minDate)) {
                $this->_error(self::MSG_MINDATE);
                return false;
            }
        } else {
            if (isset($this->_minDate)&&($value <= $this->_minDate)) {
                $this->_error(self::MSG_MINDATE_STRICT);
                return false; 
            }
        }
     
        if ($this->_maxInclusive) {
            if (isset($this->_maxDate)&&($value > $this->_maxDate)) {
                $this->_error(self::MSG_MAXDATE);
                return false;
            }
        } else {
            if (isset($this->_maxDate)&&($value >= $this->_maxDate)) {
                $this->_error(self::MSG_MAXDATE_STRICT);
                return false;
            }
        }
     
        if (($this->_weekend == true) && (date('N', strtotime($value)) < 6)) {
            $this->_error(self::MSG_WEEKEND);
            return false;
        }
     
        if (($this->_weekday == true) && (date('N', strtotime($value)) >= 6)) {
            $this->_error(self::MSG_WEEKDAY);
            return false;
        }
     
        return true;
    }
}